using System.Collections.Concurrent;
using System.Collections.Generic;
using Gj.Galaxy.Logic;
using UnityEngine;

namespace Gj.MapData
{
    public enum CheckIntMode : byte
    {
        Equal,
        Greater,
        Less
    }

    public enum CheckExistMode : byte
    {
        Exist,
        NoExist
    }

    public enum CheckSortedMode : byte
    {
        Exist,
        NoExist,
        Greater,
        Less
    }

    public class CheckBuilder
    {
        public static ConcurrentQueue<CheckBuilder> Queue = new();
        private readonly List<CheckData[]> _all = new();
        private int _alloc;
        private readonly List<CheckContent> _contents = new();
        private CheckData _current;
        private readonly List<CheckData> _part = new();

        public static CheckBuilder Get()
        {
            CheckBuilder builder = null;
            if (Queue.TryDequeue(out builder))
            {
            }

            if (builder == null) builder = new CheckBuilder();

            return builder;
        }

        internal static void Release(CheckBuilder builder)
        {
            if (builder._alloc == 0)
            {
                builder._all.Clear();
                builder._part.Clear();
                builder._contents.Clear();
                Queue.Enqueue(builder);
            }
            else
            {
                builder._alloc--;
            }
        }

        public CheckBuilder Alloc()
        {
            _alloc++;
            return this;
        }

        public CheckBuilder Parse(object[] objects)
        {
            foreach (var o in objects)
            {
                var oo = (object[])o;
                var d = new CheckData[oo.Length];
                for (var i = 0; i < oo.Length; i++) d[i] = new CheckData((object[])oo[i]);
                _all.Add(d);
            }

            return this;
        }

        public CheckBuilder And(DataType dataType, object id)
        {
            UpdateAnd();
            _current = new CheckData(dataType, id);
            return this;
        }

        public CheckBuilder Exist()
        {
            var content = new CheckContent();
            content.CheckType = CheckType.Exist;
            _contents.Add(content);
            return this;
        }

        public CheckBuilder NoExist()
        {
            var content = new CheckContent();
            content.CheckType = CheckType.NoExist;
            _contents.Add(content);
            return this;
        }

        public CheckBuilder Data(string key, int value)
        {
            var content = new CheckContent();
            content.CheckType = CheckType.Data;
            content.Key = key;
            content.Value = value;
            _contents.Add(content);
            return this;
        }

        public CheckBuilder Data(string key, int value, CheckIntMode mode)
        {
            var content = new CheckContent();
            switch (mode)
            {
                case CheckIntMode.Equal:
                    content.CheckType = CheckType.Equal;
                    break;
                case CheckIntMode.Greater:
                    content.CheckType = CheckType.Greater;
                    break;
                case CheckIntMode.Less:
                    content.CheckType = CheckType.Less;
                    break;
            }

            content.Key = key;
            content.Value = value;
            _contents.Add(content);
            return this;
        }

        public CheckBuilder Position(string key, Vector2Int position, bool equal = true)
        {
            var content = new CheckContent();
            content.CheckType = equal ? CheckType.PositionEqual : CheckType.PositionUnEqual;
            content.Key = key;
            content.Value = SerializeInt.Vector2Int(position);
            _contents.Add(content);
            return this;
        }

        public CheckBuilder List(string extend, int index, object value, CheckIntMode mode)
        {
            var content = new CheckContent();
            switch (mode)
            {
                case CheckIntMode.Equal:
                    content.CheckType = CheckType.ListEqual;
                    break;
                case CheckIntMode.Greater:
                    content.CheckType = CheckType.ListGreater;
                    break;
                case CheckIntMode.Less:
                    content.CheckType = CheckType.ListLess;
                    break;
            }

            content.Key = extend;
            content.Index = index;
            content.Value = value;
            _contents.Add(content);
            return this;
        }

        public CheckBuilder Set(string extend, object value, CheckExistMode mode)
        {
            var content = new CheckContent();
            switch (mode)
            {
                case CheckExistMode.Exist:
                    content.CheckType = CheckType.SetExist;
                    break;
                case CheckExistMode.NoExist:
                    content.CheckType = CheckType.SetNoExist;
                    break;
            }

            content.Key = extend;
            content.Value = value;
            _contents.Add(content);
            return this;
        }

        public CheckBuilder Sorted(string extend, int index, object value, CheckSortedMode mode)
        {
            var content = new CheckContent();
            switch (mode)
            {
                case CheckSortedMode.Exist:
                    content.CheckType = CheckType.SortedExist;
                    break;
                case CheckSortedMode.NoExist:
                    content.CheckType = CheckType.SortedNoExist;
                    break;
                case CheckSortedMode.Greater:
                    content.CheckType = CheckType.SortedGreater;
                    break;
                case CheckSortedMode.Less:
                    content.CheckType = CheckType.SortedLess;
                    break;
            }

            content.Key = extend;
            content.Index = index;
            content.Value = value;
            _contents.Add(content);
            return this;
        }

        public CheckBuilder Sustain(string key, int type, int delay, CheckExistMode mode)
        {
            var content = new CheckContent();
            switch (mode)
            {
                case CheckExistMode.Exist:
                    content.CheckType = CheckType.SustainTimeExist;
                    break;
                case CheckExistMode.NoExist:
                    content.CheckType = CheckType.SustainTimeNoExist;
                    break;
            }

            content.Key = key;
            content.Index = type;
            content.Value = delay;
            _contents.Add(content);
            return this;
        }

        private void UpdateOr()
        {
            if (_part.Count > 0)
            {
                _all.Add(_part.ToArray());
                _part.Clear();
            }
        }

        private void UpdateAnd()
        {
            if (_contents.Count > 0)
            {
                _current.Checks = _contents.ToArray();
                _part.Add(_current);
                _contents.Clear();
            }
        }

        public CheckBuilder Or()
        {
            UpdateAnd();
            UpdateOr();
            return this;
        }

        internal CheckData[][] Data()
        {
            UpdateAnd();
            UpdateOr();

            var data = _all.ToArray();
            Release(this);
            return data;
        }
    }
}